package com.mtcarpenter.stream;

import com.mtcarpenter.common.Fruit;
import com.mtcarpenter.common.FruitDataTest;
import org.junit.Test;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: mtcarpenter
 * @describe
 * @Date: 2019/10/7
 * @Version 1.0
 */
public class StreamApi03Test {

    /**
     * 1 forEach - 循环 stream
     */
    @Test
    public void test01(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        // 获得一个 stream 流
        Stream<Fruit> stream = fruites.stream();
        // 取出前三条
        stream.limit(3).forEach(System.out::println);
        // 已经使用了 终止操作，再次使用会报错
        stream.limit(3).forEach(System.out::println);
    }

    /**
     * 2 toArray - stream 转数组
     */
    @Test
    public void test02(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        Object[] objects = fruites.stream().map(Fruit::getName).toArray();
        for (Object object : objects) {
            System.out.println(object);
        }
    }

    /**
     * 3.anyMatch，allMatch，noneMatch
     */
    @Test
    public void test03(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        // anyMatch(Predicate p) 检查是否至少匹配一个元素
        // 检查水果价格是否超过 10
        boolean anyMatch = fruites.stream().anyMatch(s -> s.getPrice() > 10);
        System.out.println("anyMatch:检查水果价格是否超过 10 :"+anyMatch);
        // allMatch(Predicate p) 检查是否匹配的所有元素
        // 检查水果数量都超过 100
        boolean allMatch = fruites.stream().allMatch(s -> s.getNum() > 100);
        System.out.println("allMatch:检查水果数量都超过 100 :"+allMatch);
        // noneMatch(Predicate p) 检查是否没有匹配的元素
        // 检查没有 type 为 1 的元素
        boolean noneMatch = fruites.stream().noneMatch(s -> s.getType() == 1);
        System.out.println("noneMatch:检查没有 type 为 1 的元素 :"+noneMatch);

    }

    /**
     * 4.min、max、count
     */
    @Test
    public void test04(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        //min(Comparator p ) 返回流中最小值
        // 返回价格最低的水果
        Optional<Fruit> min = fruites.stream().min((o1,o2)->Double.compare(o1.getPrice(),o2.getPrice() ));
        System.out.println("最低的水果: "+min);
        // max(Comparator c) 返回流中最大值
        // 返回价格最高的水果
        Optional<Fruit> max = fruites.stream().max((o1,o2)->Double.compare(o1.getPrice(),o2.getPrice() ));
        System.out.println("价格最高的水果: "+max);
        // count 返回流中元素个数
        long count = fruites.stream().count();
        System.out.println("流中元素个数 : "+count);
    }

    /**
     * 5 reduce
     */
    @Test
    public void test05(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        // reduce(T identity ,BinaryOperator b)  将流中元素反复集合起来，得到一个值。返回 T
        //求水果总数量
        Integer numTotal = fruites.stream().map(Fruit::getNum).reduce(0, Integer::sum);
        System.out.println("水果总数量 : " + numTotal);
        Optional<Integer> reduce = fruites.stream().map(Fruit::getNum).reduce(Integer::sum);
        System.out.println("水果总数量 : " + reduce.get());
    }

    /**
     * 6 collect - list，set ，map
     */
    @Test
    public void test06(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        // collect(Collect c) 将流转换为其他形式。接收一个 Collector 接口的实现。收集、将流转换为其他形式
        // 收集水果名到 list
        System.out.println("************ 收集水果名到 list *******************");
        List<String> list = fruites.stream().map(Fruit::getName).collect(Collectors.toList());
        list.forEach(System.out::println);
        // 收集水果名到 set
        System.out.println("************ 收集水果名到 set  *******************");
        Set<String> set = fruites.stream().map(Fruit::getName).collect(Collectors.toSet());
        set.forEach(System.out::println);
        // 收集到 map,id 作为key,Fruit 对象作为 value
        System.out.println("************ 收集水果到 map   *******************");
        Map<Integer, Fruit> collect = fruites.stream().collect(Collectors.toMap(Fruit::getId, Function.identity()));
        collect.forEach( (s, fruit) -> {
            System.out.println(s+" = "+fruit);
        });
    }

    /**
     * 7 collect - joining()，groupingBy
     */
    @Test
    public void test07(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        List<String> list = Arrays.asList("a", "b", "c", "d");
        // joining()  delimiter  分隔符, prefix 前缀, suffix 后缀
        System.out.println("*************  joining 连接操作符 *********************");
        String collect = list.stream().collect(Collectors.joining("->","",""));
        System.out.println(collect);
        // groupingBy 分组
        System.out.println("*************  根据 type 进行简单分组 *********************");
        Map<Integer, List<Fruit>> collect1 = fruites.stream().collect(Collectors.groupingBy(Fruit::getType));
        collect1.forEach((k,v)->{
            System.out.println(k+"--"+v);
        });
        // 根据 type 分组求和
        System.out.println("*************  根据 type 分组求和 *************************");
        Map<Integer, Integer> collect2 = fruites.stream().collect(Collectors.groupingBy(Fruit::getType, Collectors.summingInt(Fruit::getNum)));
        collect2.forEach((k,v)->{
            System.out.println("type = "+k+" ---- 总数 = "+v);
        });
        // 求出每一个 type 不同分类的元素总个数
        System.out.println("*************  根据  type 不同分类的元素总个数 ******************");
        Map<Integer, Long> collect3 = fruites.stream().collect(Collectors.groupingBy(Fruit::getType, Collectors.counting()));
        collect3.forEach((k,v)->{
            System.out.println("type = "+k+" ---- 个数 = "+v);
        });
    }

    /**
     *  findFirst，findAny
     */
    @Test
    public void test08(){
        List<Fruit> fruites = FruitDataTest.getFruites();
        //  findFirst 获取第一个元素
        Optional<Fruit> first = fruites.stream().findFirst();
        System.out.println("获取第一个元素："+first);
        // findAny  获取任一元素
        Optional<Fruit> any = fruites.stream().findAny();
        System.out.println("获取任一元素："+any);
    }

}
